/**
 * @file uinteger.h
 * @brief 实现固定长度的无符号大整数类型，并基于该类型实现数学运算
 * @license BSD
 */

#ifndef SM_UINTEGER_H
#define SM_UINTEGER_H


#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif 

/** 定义uinteger类型的最大bit长度 */
#ifndef UINTEGER_MAX_BIT_SIZE 
#define UINTEGER_MAX_BIT_SIZE 1024
#endif

/** uinteger包含多少个uint32_t数据 */
#define UINTEGER_MAX_DIGIT_SIZE (UINTEGER_MAX_BIT_SIZE/(sizeof(uint32_t)*8))

/** 定义固定长度的无符号大整数类型，使用big-endian */
typedef struct UInteger_st {
	uint32_t ds[UINTEGER_MAX_DIGIT_SIZE];	//!< digits，放置整数的数据
} UInteger;

/**
 */
void UInteger_From(UInteger *a, const UInteger *b);

/**
 * 从byte数组构建uinteger,使用big-endian
 * @param [out] a
 * @param [in] v,size
 * @return false表示数据有丢失
 */
bool UInteger_FromBytes(UInteger* a, const uint8_t *v, size_t size);

/**
 * 从uint32_t数组构建uinteger
 * @param [out] a
 * @param [in] v,size
 * @return false表示数据有丢失
 */
bool UInteger_FromUInts(UInteger* a, const uint32_t *v, size_t size);

/**
 * 从单个uint32_t构建uinteger
 * @param [out] a
 * @param [in] v
 * @return false表示数据有丢失
 */
bool UInteger_FromUInt(UInteger* a, uint32_t v);


/**
 * 将uinteger转化成uint8_t的数据串，
 * @param [in] a
 * @param [out] v 输出的数据
 * @param [in] size v的大小
 * @return true 表示没有信息丢失，false表示有信息丢失
 */
bool UInteger_ToBytes(const UInteger* a, uint8_t *v, size_t size);

/**
 * 使用filling填充a的每一个元素
 * @param [out] a 
 * @param [in] filling
 */
void UInteger_Fill(UInteger *a, uint32_t filling);

void UInteger_Copy(const UInteger *a, UInteger *b);

/** 获取UINTEGER_MAX_DIGIT_SIZE的值 */
size_t UInteger_DigitSize(const UInteger *a);

/** 获取第i个digit的值 */
uint32_t UInteger_GetDigit(const UInteger *a, size_t i);

/** 获取UINTEGER_MAX_BIT_SIZE的值 */
size_t UInteger_BitSize(const UInteger *a);

/** 获取第i个bit的值 */
bool UInteger_GetBit(const UInteger *a, size_t i);

/** 获取sizeof(uint32_t)的值 */
size_t UInteger_DigitBitSize(const UInteger *a);

/**
 * 比较a，b两个数据的大小
 * @param [in] a,b 
 * @return <0表示a<b，==0表示a==b，>0表示a>b
 */
int UInteger_Compare(const UInteger *a, const UInteger *b);

/**
 * 比较a，b两个数据的大小，其中b的数据类型是uint32_t
 * @see UInteger_Compare
 */
int UInteger_CompareUInt(const UInteger *a, uint32_t b);

/**
 * 比较a，b两个数据的大小，其中b的数据类型是uint32_t数组
 * @see UInteger_Compare
 */
int UInteger_CompareUInts(const UInteger *a, const uint32_t *b, size_t bsize);

/**
 * 计算c = a + b, 其中a,b,c可以重复
 * @param [in] a,b
 * @param [out] c
 * @return true表示数据没有溢出，false表示数据溢出
 */
bool UInteger_Add(const UInteger *a, const UInteger *b, UInteger *c);

/**
 * 计算c = a - b，其中a,b,c可以重复
 * @param [in] a,b
 * @param [out] c
 * @return true表示数据a>=b, false表示a<b,
 */
bool UInteger_Sub(const UInteger *a, const UInteger *b, UInteger *c);

/**
 * 计算[hl] = a * b， 其中a,b,l,h可以重复
 * @param [in] a,b
 * @param [out] l,h 积的低部和高部，可以输入NULL
 * @return true 表示没有数据丢失，false表示有数据丢失，比如h为NULL,而
 */
bool UInteger_Mul(const UInteger *a, const UInteger *b, UInteger *l, UInteger *h);

/**
 * 计算q = a/b, r = a%b，其中a,b,q,r可以相同
 * @param [in] a,b
 * @param [out] q,r 商和余数，可以输入NULL
 * @return true表示没有数据丢失，
 */
bool UInteger_Div(const UInteger *a, const UInteger *b, UInteger *q, UInteger *r);

/**
 * 计算 c = a + b mod m, 其中a,b,m,c可以相同
 * @param [in] a,b,m
 * @param [out] c
 */ 
void UInteger_ModAdd(const UInteger *a, const UInteger *b, const UInteger *m, UInteger *c);

/**
 * 计算 c = a - b mod m, 其中a,b,m,c可以相同
 */
void UInteger_ModSub(const UInteger *a, const UInteger *b, const UInteger *m, UInteger *c);

/**
 * 计算 c = a * b mod m, 其中a,b,m,c可以相同
 */
void UInteger_ModMul(const UInteger *a, const UInteger *b, const UInteger *m, UInteger *c);

/**
 * 计算 c = a / b mod m，等价 c = a * b^-1 mod m，其中a,b,m,c可以相同
 * @return false表示没有该结果
 */
bool UInteger_ModDiv(const UInteger *a, const UInteger *b, const UInteger *m, UInteger *c);

/**
 * 计算 c = a^-1 mod m，
 * @return false 表示没有该结果
 */
bool UInteger_ModInv(const UInteger *a, const UInteger *m, UInteger *c);

/**
 * 计算b = ~a，其中a，b可以重复
 * @param [in] a
 * @param [out] b
 */
void UInteger_Not(const UInteger *a, UInteger *b);

/**
 * 计算c = a & b，其中a，b，c可以重复
 * @param [in] a,b
 * @param [out] c
 */
void UInteger_And(const UInteger *a, const UInteger *b, UInteger *c);

/**
 * 计算c = a | b，其中a，b，c可以重复
 * @param [in] a,b
 * @param [out] c
 */
void UInteger_Or(const UInteger *a, const UInteger *b, UInteger *c);

/**
 * 计算c = a ^ b，其中a，b，c可以重复
 * @param [in] a,b
 * @param [out] c
 */
void UInteger_Xor(const UInteger *a, const UInteger *b, UInteger *c);

void UInteger_BitAdd(const UInteger *a, const UInteger *b, UInteger *c);
void UInteger_BitSub(const UInteger *a, const UInteger *b, UInteger *c);

bool UInteger_BitMul(const UInteger *a, const UInteger *b, UInteger *c);

bool UInteger_BitDiv(const UInteger *a, const UInteger *b, UInteger *q, UInteger *r);

void UInteger_BitModAdd(const UInteger *a, const UInteger *b, const UInteger *m, UInteger *c);

void UInteger_BitModSub(const UInteger *a, const UInteger *b, const UInteger *m, UInteger *c);

void UInteger_BitModMul(const UInteger *a, const UInteger *b, const UInteger *m, UInteger *c);

void UInteger_BitModDiv(const UInteger *a, const UInteger *b, const UInteger *m, UInteger *c);
void UInteger_BitModInv(const UInteger *a, const UInteger *m, UInteger *c);

void UInteger_BitModPow(const UInteger *a, const UInteger *b, const UInteger *m,  UInteger *c);

bool UInteger_LeftShift(const UInteger *a, size_t bits, UInteger *b);
#ifdef __cplusplus
}	// extern "C" {
#endif

#endif // SM_UINTEGER_H

